package roborally.model;

import be.kuleuven.cs.som.annotate.*;

/**
 * A class of weights expressing an amount of mass
 * in grams (g).
 * 	
 * @invar   ...
 *        	| isValidWeight(getWeight())
 * 
 * @version  1.0
 * @author	Pieter Robberechts	(1e Bach Informatica)
 * @author	Jeroen Sanders 		(1e Bach Informatica)
 */
public class Weight {

	/**
	 * Initialize this new weight with given weight in units.
	 * 
	 * @param  	weightInUnits
	 *         	The weight in units for this new weight.	
	 * @effect 	...
	 *       	| setWeightInUnits(weightInUnits)
	 */
	@Raw
	public Weight(int weightInUnits) {
		setWeightInUnits(weightInUnits);
	}

	/**
	 * Initialize this new weight to 0 g.
	 * 
	 * @effect 	...
	 *       	| this(0)
	 */
	@Raw
	public Weight() {
		this(0);
	}

	/**
	 * Return the weight in units of this weight.
	 */
	@Basic
	@Raw
	public int getWeightInUnits() {
		return this.weightInUnits;
	}

	/**
	 * Check whether the given weight is a valid weight in units
	 * for any weight.
	 * 
	 * @param  	weight
	 *         	The weight to be checked.
	 * @return 	...
	 *       	| result == ( weight >= 0 && weight <= Integer.MAX_VALUE )
	 */
	public static boolean isValidWeightInUnits(int weight) {
		return weight >= 0 && weight <= Integer.MAX_VALUE;
	}

	/**
	 * Set the weight in units for this weight to the given weight
	 * in units.
	 * 
	 * @param  	weightInUnits
	 *         	The new weight in units for this weight.       
	 * @post   	...
	 * 			| if( isValidWeightInUnits(weightInUnits) )
	 *       	| 	then new.getWeightInUnits().equals(weightInUnits)
	 */
	@Raw
	public void setWeightInUnits(int weightInUnits) {
		if( isValidWeightInUnits(weightInUnits) )
			this.weightInUnits = weightInUnits;
	}

	/**
	 * Variable referencing the weight in units involved in
	 * this weight.
	 */
	private int weightInUnits;

	/**
	 * Change the value of this weight to the given 
	 * weight.
	 * 
	 * @param  	target
	 *         	The weight to be registered. 

	 * @effect 	...
	 * 			| if( target != null )
	 *       	| 	then setWeightInUnits(target.getWeightInUnits())
	 */
	public void changeValue(Weight target) {
		if( target != null )
			setWeightInUnits(target.getWeightInUnits());
	}

	/**
	 * Add the given weight to this weight.
	 * 
	 * @param  	other
	 *         	The weight to add.
	 * @effect 	...
	 * 			| if( other != null && isValidWeightInUnits(this.getWeightInUnits() + other.getWeightInUnits()) )
	 *       	| 	then this.setWeightInUnits(getWeightInUnits() + other.getWeightInUnits())
	 */
	public void add(Weight other) {
		if( other != null && isValidWeightInUnits(this.getWeightInUnits() + other.getWeightInUnits()) )
			setWeightInUnits(this.getWeightInUnits() + other.getWeightInUnits());
	}
	
	/**
	 * Subtract the given weight from this weight.
	 * 
	 * @param  	other
	 *         	The weight to subtract.
	 * @effect 	...
	 * 			| if( other != null && isValidWeightInUnits(this.getWeightInUnits() - other.getWeightInUnits()) )
	 *       	| 	then this.setWeightInUnits(getWeightInUnits() - other.getWeightInUnits())
	 */
	public void subtract(Weight other) {
		if( other != null && isValidWeightInUnits(this.getWeightInUnits() - other.getWeightInUnits()) )
			setWeightInUnits(this.getWeightInUnits() - other.getWeightInUnits());
	}
	
	/**
	 * Check whether this weight is less than the given weight.
	 * 
	 * @param  	other
	 *         	The weight to compare with.
	 * @pre    	...
	 *        	| other != null    
	 * @return 	...
	 *       	| result == (this.getWeightInUnits() < other.getWeightInUnits())
	 */
	public boolean lessThan(Weight other) {
		assert( other != null );
		return (this.getWeightInUnits() < other.getWeightInUnits());
	}
	
	/**
	 * Check whether this weight is more than the given weight.
	 * 
	 * @param  	other
	 *         	The weight to compare with.
	 * @pre    	...
	 *        	| other != null    
	 * @return 	...
	 *       	| result == (this.getWeightInUnits() > other.getWeightInUnits())
	 */
	public boolean moreThan(Weight other) {
		assert( other != null );
		return (this.getWeightInUnits() > other.getWeightInUnits());
	}

	/**
	 * Return a new weight that is identical to this weight.
	 * 
	 * @return 	...
	 *       	| (result != null) && (result != this) &&
	 *       	| (result.getWeightInUnits() == this.getWeightInUnits())
	 */
	public Weight getCopy() {
		return new Weight(getWeightInUnits());
	}

	/**
	 * Check whether this weight is identical to the
	 * given weight.
	 * 
	 * @param  	other
	 *         	The weight to compare with.
	 * @return 	...
	 *       	| result ==
	 *       	|   (other != null) &&
	 *       	|   (getWeightInUnits() == other.getWeightInUnits())
	 */
	public boolean isIdenticalTo(Weight other) {
		return (other != null) && (getWeightInUnits() == other.getWeightInUnits());
	}

	/**
	 * Return a textual representation of this weight.
	 * 
	 * @return 	...
	 *       	| result.equals( getWeightInUnits() + " g" )
	 */
	public String toString() {
		return getWeightInUnits() + " g";
	}
	
}
